package top.hhydra.mimall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import top.hhydra.mimall.entity.Cart;
import top.hhydra.mimall.entity.Product;
import top.hhydra.mimall.enums.ProductStateEnum;
import top.hhydra.mimall.enums.ResponseEnum;
import top.hhydra.mimall.form.CartAddForm;
import top.hhydra.mimall.form.CartUpdateForm;
import top.hhydra.mimall.mapper.ProductMapper;
import top.hhydra.mimall.service.ICartService;
import top.hhydra.mimall.vo.CartProductVo;
import top.hhydra.mimall.vo.CartVo;
import top.hhydra.mimall.vo.ResponseVo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @auther SaiyeEmon
 * @create 2020-02-26 23:32
 */
@Service
@Slf4j
public class ICartServiceImpl implements ICartService {

    private final static String CART_REDIS_KEY_TEMPLATE = "cart_%d";

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    @Override
    public ResponseVo<CartVo> add(Integer uid, CartAddForm form) {
        Integer quantity = 1;

        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", form.getProductId());
        Product product = productMapper.selectOne(queryWrapper);
        if (product == null
                || product.getStatus().equals(ProductStateEnum.OFF_SELL.getCode())
                || product.getStatus().equals(ProductStateEnum.DELETE.getCode())) {
            return ResponseVo.error(ResponseEnum.HAVE_NOT_PRODUCT);
        }
        if (product.getStock() <= 0) {
            return ResponseVo.error(ResponseEnum.HAVE_NOT_PRODUCT_STOCK);
        }

        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        Cart cart;
        String value = hash.get(redisKey, String.valueOf(product.getId()));
        if (StringUtils.isEmpty(value)) {
            cart = new Cart()
                    .setProductId(form.getProductId())
                    .setQuantity(quantity)
                    .setProductSelected(form.getSelected());
        } else {
            cart = gson.fromJson(value, Cart.class);
            cart.setQuantity(cart.getQuantity() + quantity);
        }

        String json = gson.toJson(cart);
        hash.put(redisKey, String.valueOf(product.getId()), json);

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> list(Integer uid) {
        CartVo cartVo = new CartVo();
        List<CartProductVo> cartProductVoList = new ArrayList<>();
        cartVo.setCartProductVoList(cartProductVoList);
        Boolean selectedAll = true;
        BigDecimal cartTotalPrice = BigDecimal.ZERO;
        Integer cartTotalQuantity = 0;

        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();

        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        Map<String, String> entries = hash.entries(redisKey);
        queryWrapper.in("id", entries.keySet());
        List<Product> products = productMapper.selectList(queryWrapper);
        for (Product product : products) {
            Cart cart = gson.fromJson(entries.get(String.valueOf(product.getId())), Cart.class);
            CartProductVo cartProductVo = new CartProductVo(product.getId(),
                    cart.getQuantity(),
                    product.getName(),
                    product.getSubtitle(),
                    product.getMainImage(),
                    product.getPrice(),
                    product.getStatus(),
                    product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())),
                    product.getStock(),
                    cart.getProductSelected()
            );
            cartProductVoList.add(cartProductVo);

            if (!cart.getProductSelected()) {
                selectedAll = false;
            }

            if (cart.getProductSelected()) {
                cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
            }

            cartTotalQuantity += cart.getQuantity();
        }
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setSelectedAll(selectedAll);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> update(Integer uid, Integer productId, CartUpdateForm form) {
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        String value = hash.get(redisKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            return ResponseVo.error(ResponseEnum.HAVE_NOT_PRODUCT);
        }

        Cart cart = gson.fromJson(value, Cart.class);
        if (form.getSelected() != null) {
            cart.setProductSelected(form.getSelected());
        }
        if (form.getQuantity() != null && form.getQuantity() >= 0) {
            cart.setQuantity(form.getQuantity());
        }

        hash.put(redisKey, String.valueOf(productId),gson.toJson(cart));
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        String value = hash.get(redisKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            return ResponseVo.error(ResponseEnum.HAVE_NOT_PRODUCT);
        }
        hash.delete(redisKey, String.valueOf(productId));
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        Map<String, String> entries = hash.entries(redisKey);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            cart.setProductSelected(true);
            hash.put(redisKey,entry.getKey(),gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        Map<String, String> entries = hash.entries(redisKey);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            cart.setProductSelected(false);
            hash.put(redisKey,entry.getKey(),gson.toJson(cart));
        }
        return list(uid);
    }

    @Override
    public ResponseVo<Integer> sum(Integer uid) {
        Integer sum = 0;
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        Map<String, String> entries = hash.entries(redisKey);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);
            sum += cart.getQuantity();
        }
        return ResponseVo.success(sum);
    }
}
